Setup
library(magrittr)
library(tidyverse)
library(glue)
library(arrow)
library(matric)
batch <- params$batch
futile.logger::flog.info(glue("Batch = {batch}"))
INFO [2021-04-18 06:13:47] Batch = 2020_11_04_CPJUMP1
experiment <- as.data.frame(params$experiment)
futile.logger::flog.info(glue("Experiment = {experiment}"))
INFO [2021-04-18 06:13:47] Experiment = Standard
INFO [2021-04-18 06:13:47] Experiment = Compound
INFO [2021-04-18 06:13:47] Experiment = U2OS
INFO [2021-04-18 06:13:47] Experiment = 48
data_level <- params$data_level
futile.logger::flog.info(glue("Data level = {data_level}"))
INFO [2021-04-18 06:13:47] Data level = normalized
if (params$normalization == "whole_plate") {
norm_suffix <- ""
} else if (params$normalization == "negcon") {
norm_suffix <- "_negcon"
}
sprintf("Normalization = %s. Using suffix = '%s'", params$normalization, norm_suffix)
[1] "Normalization = negcon. Using suffix = '_negcon'"
filename_prefix_profiles <- glue("{batch}_all_{data_level}{norm_suffix}")
Load
parquet_file_recoded <-
glue("{batch}/{filename_prefix_profiles}_recoded_aggregated.parquet")
if (file.exists(parquet_file_recoded) && !params$force_recompute) {
parquet_file <- parquet_file_recoded
futile.logger::flog.info(glue("Loading {parquet_file} ..."))
stopifnot(file.exists(parquet_file))
profiles <-
read_parquet(parquet_file)
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
} else {
parquet_file <-
glue("../collated/{batch}/{filename_prefix_profiles}.parquet")
futile.logger::flog.info(glue("Loading {parquet_file} ..."))
stopifnot(file.exists(parquet_file))
profiles <-
read_parquet(parquet_file)
# if(!is.null(experiment)) {
# profiles <- profiles %>% inner_join(experiment)
# }
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
metadata_cols <-
str_subset(names(profiles), "Metadata_")
variables <-
params$variable_groups %>%
unlist() %>%
map(function(pattern)
str_subset(variables, pattern = pattern)) %>%
unlist()
profiles <-
profiles %>%
select(all_of(c(metadata_cols, variables)))
variables <-
str_subset(names(profiles), "Metadata_", negate = TRUE)
profiles <-
profiles %>%
group_by(across(params$strata_replicate)) %>%
summarize(across(all_of(variables), median),
.groups = "keep")
attr(profiles, "variable_groups") <- params$variable_groups
parquet_file <-
parquet_file_recoded
futile.logger::flog.info(glue("Writing {parquet_file} ..."))
profiles %>%
write_parquet(parquet_file,
compression = "gzip",
compression_level = 9)
}
INFO [2021-04-18 06:13:48] Loading ../collated/2020_11_04_CPJUMP1/2020_11_04_CPJUMP1_all_normalized_negcon.parquet ...
INFO [2021-04-18 06:25:53] Writing 2020_11_04_CPJUMP1/2020_11_04_CPJUMP1_all_normalized_negcon_recoded_aggregated.parquet ...
Plot
profiles_enriched %>%
inner_join(experiment) %>%
pivot_longer(-matches("Metadata"),
names_to = "feature_group")%>%
ggplot(aes(feature_group, value)) +
geom_boxplot() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")

profiles_enriched %>%
inner_join(experiment) %>%
pivot_longer(-matches("Metadata"),
names_to = "feature_group") %>%
ggplot(aes(feature_group, value, group = Metadata_Well)) +
geom_line(alpha = .09) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
facet_wrap(~Metadata_negcon_or_other, ncol = 1)
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")

library(plotly)
df <-
profiles_enriched %>%
inner_join(experiment)
Joining, by = c("Metadata_experiment_condition", "Metadata_experiment_type", "Metadata_cell_line", "Metadata_timepoint")
dimensions <- list(
list(label = "Intensity_RNA",
values = ~ Intensity_RNA),
list(label = 'Intensity_DNA',
values = ~ Intensity_DNA)
)
dimensions <-
variables_enriched %>%
map(function(variable) {
list(label = variable,
values = df[[variable]])
})
df %>%
plot_ly(width = 1000,
height = 600) %>%
add_trace(type = 'parcoords',
dimensions = dimensions)
LS0tCnRpdGxlOiAiRmVhdHVyZSBhbmFseXNpcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMycKICAgIGRmX3ByaW50OiBwYWdlZApwYXJhbXM6CiAgZm9yY2VfcmVjb21wdXRlOiBGQUxTRQogIGJhdGNoOiAyMDIwXzExXzA0X0NQSlVNUDEKICBkYXRhX2xldmVsOiBub3JtYWxpemVkCiAgbm9ybWFsaXphdGlvbjogbmVnY29uCiAgZXhwZXJpbWVudDogCiAgICB2YWx1ZToKICAgICAgTWV0YWRhdGFfZXhwZXJpbWVudF9jb25kaXRpb246IFN0YW5kYXJkCiAgICAgIE1ldGFkYXRhX2V4cGVyaW1lbnRfdHlwZTogQ29tcG91bmQKICAgICAgTWV0YWRhdGFfY2VsbF9saW5lOiBVMk9TCiAgICAgIE1ldGFkYXRhX3RpbWVwb2ludDogIjQ4IgogIG5lc3RpbmdfbGV2ZWxfMDoKICAgIHZhbHVlOgogICAgICAtIE1ldGFkYXRhX2V4cGVyaW1lbnRfY29uZGl0aW9uCiAgICAgIC0gTWV0YWRhdGFfZXhwZXJpbWVudF90eXBlCiAgICAgIC0gTWV0YWRhdGFfY2VsbF9saW5lCiAgICAgIC0gTWV0YWRhdGFfdGltZXBvaW50CiAgc3RyYXRhX3JlcGxpY2F0ZToKICAgIHZhbHVlOgogICAgICAtIE1ldGFkYXRhX2V4cGVyaW1lbnRfY29uZGl0aW9uCiAgICAgIC0gTWV0YWRhdGFfZXhwZXJpbWVudF90eXBlCiAgICAgIC0gTWV0YWRhdGFfY2VsbF9saW5lCiAgICAgIC0gTWV0YWRhdGFfdGltZXBvaW50CiAgICAgIC0gTWV0YWRhdGFfcGxhdGVfbWFwX25hbWUKICAgICAgLSBNZXRhZGF0YV9XZWxsCiAgICAgIC0gTWV0YWRhdGFfZ2VuZXMKICAgICAgLSBNZXRhZGF0YV9wZXJ0X3R5cGUKICAgICAgLSBNZXRhZGF0YV9jb250cm9sX3R5cGUKICAgICAgLSBNZXRhZGF0YV9QbGF0ZV9NYXBfTmFtZQogICAgICAtIE1ldGFkYXRhX25lZ2Nvbl9jb250cm9sX3R5cGUKICAgICAgLSBNZXRhZGF0YV90YXJnZXRfc2VxdWVuY2UKICAgICAgLSBNZXRhZGF0YV9tZ19wZXJfbWwKICAgICAgLSBNZXRhZGF0YV9tbW9sZXNfcGVyX2xpdGVyCiAgICAgIC0gTWV0YWRhdGFfc29sdmVudAogICAgICAtIE1ldGFkYXRhX3RhcmdldAogICAgICAtIE1ldGFkYXRhX3BlcnRfaW5hbWUKICAgICAgLSBNZXRhZGF0YV9icm9hZF9zYW1wbGUKICAgICAgLSBNZXRhZGF0YV9wdWJjaGVtX2NpZAogICAgICAtIE1ldGFkYXRhX0luQ2hJS2V5CiAgICAgIC0gTWV0YWRhdGFfZ2VuZQogICAgICAtIE1ldGFkYXRhX25lZ2Nvbl9vcl9vdGhlcgogICAgICAtIE1ldGFkYXRhX25lZ2Nvbl9jb250cm9sX3R5cGVfdHJpbW1lZAogIHZhcmlhYmxlX2dyb3VwczoKICAgIHZhbHVlOgogICAgICAtIHhBcmVhOiBfQXJlYVNoYXBlX0FyZWEkCiAgICAgIC0geFNoYXBlOiBBcmVhU2hhcGUKICAgICAgLSB4TmVpZ2g6IE5laWdoYm9ycwogICAgICAtIHhDb3JyOiBDb3JyZWxhdGlvbgogICAgICAtIFRleF9BR1A6ICgoVGV4dHVyZXxHcmFudWxhcml0eXxSYWRpYWxEaXN0cmlidXRpb24pXy4qXyhBR1ApKQogICAgICAtIFRleF9ETkE6ICgoVGV4dHVyZXxHcmFudWxhcml0eXxSYWRpYWxEaXN0cmlidXRpb24pXy4qXyhETkEpKQogICAgICAtIFRleF9FUjogKChUZXh0dXJlfEdyYW51bGFyaXR5fFJhZGlhbERpc3RyaWJ1dGlvbilfLipfKEVSKSkKICAgICAgLSBUZXhfTWl0bzogKChUZXh0dXJlfEdyYW51bGFyaXR5fFJhZGlhbERpc3RyaWJ1dGlvbilfLipfKE1pdG8pKQogICAgICAtIFRleF9STkE6ICgoVGV4dHVyZXxHcmFudWxhcml0eXxSYWRpYWxEaXN0cmlidXRpb24pXy4qXyhSTkEpKQogICAgICAtIEludF9BR1A6ICgoSW50ZW5zaXR5KV8uKl8oQUdQKSkKICAgICAgLSBJbnRfRE5BOiAoKEludGVuc2l0eSlfLipfKEROQSkpCiAgICAgIC0gSW50X0VSOiAoKEludGVuc2l0eSlfLipfKEVSKSkKICAgICAgLSBJbnRfTWl0bzogKChJbnRlbnNpdHkpXy4qXyhNaXRvKSkKICAgICAgLSBJbnRfUk5BOiAoKEludGVuc2l0eSlfLipfKFJOQSkpCi0tLQoKIyBTZXR1cAoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShtYWdyaXR0cikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShhcnJvdykKbGlicmFyeShtYXRyaWMpCmBgYAoKCmBgYHtyfQpiYXRjaCA8LSBwYXJhbXMkYmF0Y2gKZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIkJhdGNoID0ge2JhdGNofSIpKQpgYGAKYGBge3J9CmV4cGVyaW1lbnQgPC0gYXMuZGF0YS5mcmFtZShwYXJhbXMkZXhwZXJpbWVudCkKZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIkV4cGVyaW1lbnQgPSB7ZXhwZXJpbWVudH0iKSkKYGBgCgoKYGBge3J9CmRhdGFfbGV2ZWwgPC0gcGFyYW1zJGRhdGFfbGV2ZWwKZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIkRhdGEgbGV2ZWwgPSB7ZGF0YV9sZXZlbH0iKSkKYGBgCgoKYGBge3J9CmlmIChwYXJhbXMkbm9ybWFsaXphdGlvbiA9PSAid2hvbGVfcGxhdGUiKSB7CiAgbm9ybV9zdWZmaXggPC0gIiIKfSBlbHNlIGlmIChwYXJhbXMkbm9ybWFsaXphdGlvbiA9PSAibmVnY29uIikgewogIG5vcm1fc3VmZml4IDwtICJfbmVnY29uIgp9CnNwcmludGYoIk5vcm1hbGl6YXRpb24gPSAlcy4gVXNpbmcgc3VmZml4ID0gJyVzJyIsIHBhcmFtcyRub3JtYWxpemF0aW9uLCBub3JtX3N1ZmZpeCkKYGBgCgoKYGBge3J9CmZpbGVuYW1lX3ByZWZpeF9wcm9maWxlcyA8LSBnbHVlKCJ7YmF0Y2h9X2FsbF97ZGF0YV9sZXZlbH17bm9ybV9zdWZmaXh9IikKYGBgCgojIExvYWQKCmBgYHtyfQpwYXJxdWV0X2ZpbGVfcmVjb2RlZCA8LQogIGdsdWUoIntiYXRjaH0ve2ZpbGVuYW1lX3ByZWZpeF9wcm9maWxlc31fcmVjb2RlZF9hZ2dyZWdhdGVkLnBhcnF1ZXQiKQoKaWYgKGZpbGUuZXhpc3RzKHBhcnF1ZXRfZmlsZV9yZWNvZGVkKSAmJiAhcGFyYW1zJGZvcmNlX3JlY29tcHV0ZSkgewogIHBhcnF1ZXRfZmlsZSA8LSBwYXJxdWV0X2ZpbGVfcmVjb2RlZAogIAogIGZ1dGlsZS5sb2dnZXI6OmZsb2cuaW5mbyhnbHVlKCJMb2FkaW5nIHtwYXJxdWV0X2ZpbGV9IC4uLiIpKQogIAogIHN0b3BpZm5vdChmaWxlLmV4aXN0cyhwYXJxdWV0X2ZpbGUpKQogIAogIHByb2ZpbGVzIDwtCiAgICByZWFkX3BhcnF1ZXQocGFycXVldF9maWxlKQogIAogIHZhcmlhYmxlcyA8LQogICAgc3RyX3N1YnNldChuYW1lcyhwcm9maWxlcyksICJNZXRhZGF0YV8iLCBuZWdhdGUgPSBUUlVFKQogIAp9IGVsc2UgewogIAogIHBhcnF1ZXRfZmlsZSA8LQogICAgZ2x1ZSgiLi4vY29sbGF0ZWQve2JhdGNofS97ZmlsZW5hbWVfcHJlZml4X3Byb2ZpbGVzfS5wYXJxdWV0IikKICAKICBmdXRpbGUubG9nZ2VyOjpmbG9nLmluZm8oZ2x1ZSgiTG9hZGluZyB7cGFycXVldF9maWxlfSAuLi4iKSkKICAKICBzdG9waWZub3QoZmlsZS5leGlzdHMocGFycXVldF9maWxlKSkKICAKICBwcm9maWxlcyA8LQogICAgcmVhZF9wYXJxdWV0KHBhcnF1ZXRfZmlsZSkKICAKICAjIGlmKCFpcy5udWxsKGV4cGVyaW1lbnQpKSB7CiAgIyAgIHByb2ZpbGVzIDwtIHByb2ZpbGVzICU+JSBpbm5lcl9qb2luKGV4cGVyaW1lbnQpCiAgIyB9CiAgCiAgdmFyaWFibGVzIDwtCiAgICBzdHJfc3Vic2V0KG5hbWVzKHByb2ZpbGVzKSwgIk1ldGFkYXRhXyIsIG5lZ2F0ZSA9IFRSVUUpCiAgCiAgbWV0YWRhdGFfY29scyA8LQogICAgc3RyX3N1YnNldChuYW1lcyhwcm9maWxlcyksICJNZXRhZGF0YV8iKQogIAogIHZhcmlhYmxlcyA8LQogICAgcGFyYW1zJHZhcmlhYmxlX2dyb3VwcyAlPiUKICAgIHVubGlzdCgpICU+JQogICAgbWFwKGZ1bmN0aW9uKHBhdHRlcm4pCiAgICAgIHN0cl9zdWJzZXQodmFyaWFibGVzLCBwYXR0ZXJuID0gcGF0dGVybikpICU+JQogICAgdW5saXN0KCkKICAKICBwcm9maWxlcyA8LQogICAgcHJvZmlsZXMgJT4lCiAgICBzZWxlY3QoYWxsX29mKGMobWV0YWRhdGFfY29scywgdmFyaWFibGVzKSkpCiAgCiAgdmFyaWFibGVzIDwtCiAgICBzdHJfc3Vic2V0KG5hbWVzKHByb2ZpbGVzKSwgIk1ldGFkYXRhXyIsIG5lZ2F0ZSA9IFRSVUUpCiAgCiAgcHJvZmlsZXMgPC0KICAgIHByb2ZpbGVzICU+JQogICAgZ3JvdXBfYnkoYWNyb3NzKHBhcmFtcyRzdHJhdGFfcmVwbGljYXRlKSkgJT4lCiAgICBzdW1tYXJpemUoYWNyb3NzKGFsbF9vZih2YXJpYWJsZXMpLCBtZWRpYW4pLAogICAgICAgICAgICAgIC5ncm91cHMgPSAia2VlcCIpCiAgCiAgYXR0cihwcm9maWxlcywgInZhcmlhYmxlX2dyb3VwcyIpIDwtIHBhcmFtcyR2YXJpYWJsZV9ncm91cHMKICAKICBwYXJxdWV0X2ZpbGUgPC0KICAgIHBhcnF1ZXRfZmlsZV9yZWNvZGVkCiAgCiAgZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIldyaXRpbmcge3BhcnF1ZXRfZmlsZX0gLi4uIikpCiAgCiAgcHJvZmlsZXMgJT4lCiAgICB3cml0ZV9wYXJxdWV0KHBhcnF1ZXRfZmlsZSwKICAgICAgICAgICAgICAgICAgY29tcHJlc3Npb24gPSAiZ3ppcCIsCiAgICAgICAgICAgICAgICAgIGNvbXByZXNzaW9uX2xldmVsID0gOSkKfQpgYGAKCiMgVHJhbnNmb3JtCgojIyBGdW5jdGlvbnMKCmBgYHtyfQpnZXRfYmV0YSA8LSBmdW5jdGlvbih4ID0gNSwgeSA9IDAuOTkpIHsKICAtbG9nKDEgLyB5IC0gMSkgLyB4Cn0KCmFic19sb2dpc3RpYyA8LSBmdW5jdGlvbih4LCBiZXRhID0gZ2V0X2JldGEoKSkgewogIDIgLyAoMSArIGV4cCgtYWJzKHgpICogYmV0YSkpIC0gMQp9CgpjeXRvbWluZXJfdmFyaWFibGVfZ3JvdXBfZW5yaWNobWVudCA8LQogIGZ1bmN0aW9uKHBvcHVsYXRpb24sCiAgICAgICAgICAgdmFyaWFibGVzLAogICAgICAgICAgIHZhcmlhYmxlX2dyb3VwcywKICAgICAgICAgICBzaWdtb2lkX2Z1bmN0aW9uID0gYWJzX2xvZ2lzdGljLAogICAgICAgICAgIC4uLikgewogICAgCiAgICB2YXJpYWJsZXNfZ3JvdXBfbGlzdHMgPC0KICAgICAgdmFyaWFibGVfZ3JvdXBzICU+JQogICAgICB1bmxpc3QoKSAlPiUKICAgICAgbmFtZXMoKSAlPiUKICAgICAgc2V0X25hbWVzKCkgJT4lCiAgICAgIHB1cnJyOjptYXAoZnVuY3Rpb24odmFyaWFibGVfZ3JvdXApIHsKICAgICAgICBzdHJpbmdyOjpzdHJfc3Vic2V0KHZhcmlhYmxlcywgdmFyaWFibGVfZ3JvdXApCiAgICAgIH0pIAoKICAgIHBvcHVsYXRpb25fZGF0YV90cmFuc2Zvcm1lZCA8LQogICAgICB2YXJpYWJsZXNfZ3JvdXBfbGlzdHMgJT4lCiAgICAgIG1hcF9kZmMoZnVuY3Rpb24odmFyaWFibGVzX2dyb3VwX2xpc3QpIHsKICAgICAgICBwb3B1bGF0aW9uICU+JQogICAgICAgICAgZHBseXI6OnNlbGVjdChhbGxfb2YodmFyaWFibGVzX2dyb3VwX2xpc3QpKSAlPiUKICAgICAgICAgIGRwbHlyOjptdXRhdGUoYWNyb3NzKGFsbF9vZih2YXJpYWJsZXNfZ3JvdXBfbGlzdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaWdtb2lkX2Z1bmN0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKSkgJT4lCiAgICAgICAgICBkcGx5cjo6dW5ncm91cCgpICU+JQogICAgICAgICAgZHBseXI6OnJvd3dpc2UoKSAlPiUKICAgICAgICAgIGRwbHlyOjp0cmFuc211dGUobl9hYm92ZSA9IHJvdW5kKHN1bSgKICAgICAgICAgICAgZHBseXI6OmNfYWNyb3NzKGV2ZXJ5dGhpbmcoKSkgLwogICAgICAgICAgICAgIGxlbmd0aCh2YXJpYWJsZXNfZ3JvdXBfbGlzdCksCiAgICAgICAgICAgIG5hLnJtID0gVAogICAgICAgICAgKSwgMikpICU+JQogICAgICAgICAgZHBseXI6OnB1bGwobl9hYm92ZSkKICAgICAgfSkKICAgIAogICAgcG9wdWxhdGlvbl9tZXRhZGF0YSA8LQogICAgICBwb3B1bGF0aW9uICU+JQogICAgICBkcGx5cjo6c2VsZWN0KC1hbGxfb2YodmFyaWFibGVzKSkKICAgIAogICAgZW5yaWNoZWQgPC0KICAgICAgZHBseXI6OmJpbmRfY29scyhwb3B1bGF0aW9uX21ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGF0YV90cmFuc2Zvcm1lZCkKICAgIAogICAgZW5yaWNoZWQKICAgIAogIH0KYGBgCgojIyBFeGVjdXRlCgpgYGB7cn0KcGFycXVldF9maWxlIDwtCiAgZ2x1ZSgie2JhdGNofS97ZmlsZW5hbWVfcHJlZml4X3Byb2ZpbGVzfV9lbnJpY2hlZC5wYXJxdWV0IikKCmlmIChmaWxlLmV4aXN0cyhwYXJxdWV0X2ZpbGUpICYgIXBhcmFtcyRmb3JjZV9yZWNvbXB1dGUpIHsKICBmdXRpbGUubG9nZ2VyOjpmbG9nLmluZm8oZ2x1ZSgiUmVhZGluZyB7cGFycXVldF9maWxlfSAuLi4iKSkKICAKICBwcm9maWxlc19lbnJpY2hlZCA8LQogICAgcmVhZF9wYXJxdWV0KHBhcnF1ZXRfZmlsZSkKICAKfSBlbHNlIHsKICAKICBwcm9maWxlc19lbnJpY2hlZCA8LQogICAgcHJvZmlsZXMgJT4lCiAgICBncm91cF9ieShhY3Jvc3MocGFyYW1zJHN0cmF0YV9yZXBsaWNhdGUpKSAlPiUKICAgIHN1bW1hcml6ZShhY3Jvc3MoYWxsX29mKHZhcmlhYmxlcyksIG1lZGlhbiksIC5ncm91cHMgPSAia2VlcCIpICU+JQogICAgZ3JvdXBfYnkoYWNyb3NzKHBhcmFtcyRuZXN0aW5nX2xldmVsXzApKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgY3l0b21pbmVyX3ZhcmlhYmxlX2dyb3VwX2VucmljaG1lbnQoCiAgICAgICAgY3VyX2RhdGFfYWxsKCksCiAgICAgICAgdmFyaWFibGVzID0gdmFyaWFibGVzLAogICAgICAgIHZhcmlhYmxlX2dyb3VwcyA9IHBhcmFtcyR2YXJpYWJsZV9ncm91cHMKICAgICAgKSwKICAgICAgLmdyb3VwcyA9ICJrZWVwIgogICAgKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogIGF0dHIocHJvZmlsZXMsICJ2YXJpYWJsZV9ncm91cHMiKSA8LSBwYXJhbXMkdmFyaWFibGVfZ3JvdXBzCiAgCiAgZnV0aWxlLmxvZ2dlcjo6ZmxvZy5pbmZvKGdsdWUoIldyaXRpbmcge3BhcnF1ZXRfZmlsZX0gLi4uIikpCiAgCiAgcHJvZmlsZXNfZW5yaWNoZWQgJT4lCiAgICB3cml0ZV9wYXJxdWV0KHBhcnF1ZXRfZmlsZSwKICAgICAgICAgICAgICAgICAgY29tcHJlc3Npb24gPSAiZ3ppcCIsCiAgICAgICAgICAgICAgICAgIGNvbXByZXNzaW9uX2xldmVsID0gOSkKICAKfQoKdmFyaWFibGVzX2VucmljaGVkIDwtCiAgc3RyX3N1YnNldChuYW1lcyhwcm9maWxlc19lbnJpY2hlZCksICJNZXRhZGF0YV8iLCBuZWdhdGUgPSBUUlVFKQpgYGAKCiMgUGxvdAoKYGBge3J9CnByb2ZpbGVzX2VucmljaGVkICU+JSAKICBpbm5lcl9qb2luKGV4cGVyaW1lbnQpICU+JQogIHBpdm90X2xvbmdlcigtbWF0Y2hlcygiTWV0YWRhdGEiKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImZlYXR1cmVfZ3JvdXAiKSU+JSAKICBnZ3Bsb3QoYWVzKGZlYXR1cmVfZ3JvdXAsIHZhbHVlKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkKYGBgCgpgYGB7cn0KcHJvZmlsZXNfZW5yaWNoZWQgJT4lIAogIGlubmVyX2pvaW4oZXhwZXJpbWVudCkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1tYXRjaGVzKCJNZXRhZGF0YSIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiZmVhdHVyZV9ncm91cCIpICU+JSAKICBnZ3Bsb3QoYWVzKGZlYXR1cmVfZ3JvdXAsIHZhbHVlLCBncm91cCA9IE1ldGFkYXRhX1dlbGwpKSArIAogIGdlb21fbGluZShhbHBoYSA9IC4wOSkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSkpICsgCiAgZmFjZXRfd3JhcCh+TWV0YWRhdGFfbmVnY29uX29yX290aGVyLCBuY29sID0gMSkKYGBgCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKCmRmIDwtIAogIHByb2ZpbGVzX2VucmljaGVkICU+JQogIGlubmVyX2pvaW4oZXhwZXJpbWVudCkKCmRpbWVuc2lvbnMgPC0gbGlzdCgKICBsaXN0KGxhYmVsID0gIkludGVuc2l0eV9STkEiLAogICAgICAgdmFsdWVzID0gfiBJbnRlbnNpdHlfUk5BKSwKICBsaXN0KGxhYmVsID0gJ0ludGVuc2l0eV9ETkEnLAogICAgICAgdmFsdWVzID0gfiBJbnRlbnNpdHlfRE5BKQopCgpkaW1lbnNpb25zIDwtCiAgdmFyaWFibGVzX2VucmljaGVkICU+JQogIG1hcChmdW5jdGlvbih2YXJpYWJsZSkgewogICAgbGlzdChsYWJlbCA9IHZhcmlhYmxlLAogICAgICAgICB2YWx1ZXMgPSBkZltbdmFyaWFibGVdXSkKICB9KQoKZGYgJT4lCiAgcGxvdF9seSh3aWR0aCA9IDEwMDAsIAogICAgICAgICAgaGVpZ2h0ID0gNjAwKSAlPiUKICBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLAogICAgICAgICAgICBkaW1lbnNpb25zID0gZGltZW5zaW9ucykKYGBgCgoKCgo=